#ifndef __PLAYER_H__
#define __PLAYER_H__

#define PLAYERS_PER_TEAM_MAX 1000
#define NUMTEAMS 2

// Player state bit vector
#define PLAYER_ON_TEAM_1	0x01
#define PLAYER_ON_TEAM_2	0x02
#define PLAYER_HAS_FLAG_1	0x04
#define PLAYER_HAS_FLAG_2	0x08
#define PLAYER_AT_HOME		0x10
#define PLAYER_IN_JAIL		0x20
#define PLAYER_HAS_BOMBS	0x40

// structure declarations defined elsewhere
struct CellStruct;
struct Maze_Struct;

typedef struct PlayerStruct {
  int socketId;
  struct CellStruct *cellPtr;
  uint16_t id;
  uint64_t state;
  struct PlayerStruct *next;
} Player;

typedef struct TeamStruct {
  Player *playerListPtr;
  uint16_t teamNo;
  uint16_t numPlayers;
} Team;

// global variable
extern Team Teams[NUMTEAMS];

// accessors
#define PLAYER_BELONGS_TO_TEAM_1(p) (p->state & PLAYER_ON_TEAM_1)
#define PLAYER_BELONGS_TO_TEAM_2(p) (p->state & PLAYER_ON_TEAM_2)
#define PLAYER_POSSESS_FLAG_1(p) (p->state & PLAYER_HAS_FLAG_1)
#define PLAYER_POSSESS_FLAG_2(p) (p->state & PLAYER_HAS_FLAG_2)
#define PLAYER_POSSESS_BOMBS(p) (p->state & PLAYER_HAS_BOMBS)
// mutators
#define PLAYER_TOGGLE_IN_JAIL(p) (p->state ^= PLAYER_IN_JAIL)
#define PLAYER_TOGGLE_HAS_FLAG_1(p) (p->state ^= PLAYER_HAS_FLAG_1)
#define PLAYER_TOGGLE_HAS_FLAG_2(p) (p->state ^= PLAYER_HAS_FLAG_2)
#define PLAYER_TOGGLE_HAS_BOMBS(p) (p->state ^= PLAYER_HAS_BOMBS)

// return values for get state accessor
#define	PLAYER_PLAYER_ON_TEAM_1		1
#define	PLAYER_PLAYER_ON_TEAM_2		2
#define PLAYER_PLAYER_HAS_FLAG_1	3
#define PLAYER_PLAYER_HAS_FLAG_2 	4
#define PLAYER_PLAYER_IN_JAIL 		5
#define PLAYER_PLAYER_AT_HOME 		6
#define PLAYER_PLAYER_HAS_BOMBS 	7

static inline uint64_t getPlayerState(Player *p) {
  if (p->state & PLAYER_HAS_FLAG_1) return PLAYER_PLAYER_HAS_FLAG_1;
  if (p->state & PLAYER_HAS_FLAG_2) return PLAYER_PLAYER_HAS_FLAG_2;
  if (p->state & PLAYER_IN_JAIL) 	return PLAYER_PLAYER_IN_JAIL;
  if (p->state & PLAYER_ON_TEAM_2)  return PLAYER_PLAYER_AT_HOME;
  if (p->state & PLAYER_HAS_BOMBS)  return PLAYER_PLAYER_HAS_BOMBS;
  if (p->state & PLAYER_ON_TEAM_2)  return PLAYER_PLAYER_ON_TEAM_2;
							   else return PLAYER_PLAYER_ON_TEAM_1;
}

/** player.c function declarations **/
uint16_t player_init();
Player * player_add(struct Maze_Struct *m);
uint16_t player_dump(Player *p);
uint16_t player_dump_team(uint16_t teamNo);
uint16_t player_remove(Player *p);
int player_tag(struct Maze_Struct *m, struct CellStruct *c, uint16_t teamNo);
uint16_t player_pickup (int sockfd, Player *p);
uint16_t player_drop (int sockfd, Player *p);

#endif
